JBoss Community Archive (Read Only)

Infinispan 5.1

Interacting With Hot Rod Server From Within Same JVM

Introduction

Normally, a Hot Rod server is accessed via a Hot Rod protocol client such as the Java Hot Rod client. However, there might be situations where not only do you want to access the Hot Rod server remotely, you might also want to access it locally from within the same JVM that the Hot Rod server is running. For example, you might have an Infinispan cache pushing changes via the RemoteCacheStore to a Hot Rod server, and if the cache goes down, you might want to access the data directly from the Hot Rod server itself.

In this situations, we have to remember that the Hot Rod protocol specifies that keys and values are stored as byte arrays. This means that if the client code, using an existing Hot Rod client, stored Strings or Integers, or any other complex serializable or externalizable object, you won't be able to retrieve these objects straight from the cache that the Hot Rod server uses.

To actually get the fully constructed objects that you're after, you're gonna need to take the byte arrays stored within the Hot Rod server and unmarshall them into something that you can use. In the future, this is something that might be done for you, as suggested in ISPN-706, but for the time being, clients wanting to access Hot Rod server data will have to do it themselves.

Two different use cases need to be differentiated at this stage and to explain how to transform the Hot Rod server data into something usable, we'll assume that the clients are java clients:

Data Stored Directly Via A Hot Rod Client

The most common case is for a client to use a Hot Rod client library directly to store data in the Hot Rod server. In this case, assuming that the client used the existing Java Hot Rod client, the default marshaller used to marshall objects into byte arrays is the GenericJBossMarshaller. So, if a user wants to read data from the Hot Rod server directly, it would need to execute something along the lines of:

import org.infinispan.marshall.jboss.GenericJBossMarshaller;
import org.infinispan.util.ByteArrayKey;
import org.infinispan.server.core.CacheValue;
...

// Create a new instance of the marshaller:
GenericJBossMarshaller marshaller = new GenericJBossMarshaller();
Object key = ...

// Take the cache key and convert into a byte array,
// and wrap it with an instance of ByteArrayKey
ByteArrayKey bytesKey = new ByteArrayKey(marshaller.objectToByteBuffer(key));

// Internally, Hot Rod stores values wrapped in a CacheValue, so retrieve it
CacheValue cacheValue = (CacheValue) cache.get(bytesKey);

// Take the data part which is byte array and unmarshall it to retrieve the value
Object value = marshaller.objectFromByteBuffer(cacheValue.data());

If you want to store data directly in the HotRod server, you'd have to execute something like this:

import org.infinispan.marshall.jboss.GenericJBossMarshaller;
import org.infinispan.util.ByteArrayKey;
import org.infinispan.server.core.CacheValue;
...

// Create a new instance of the marshaller:
GenericJBossMarshaller marshaller = new GenericJBossMarshaller();
Object key = ...
Object value = ...

// Take the cache key and convert into a byte array, 
// and wrap it with an instance of ByteArrayKey
ByteArrayKey bytesKey = new ByteArrayKey(marshaller.objectToByteBuffer(key));

// Internally, Hot Rod stores values wrapped in a CacheValue, so create instance
// Remember that you need to give it a version number, so either:
// 1. Increment previous value's version
// 2. Or generate a new version number that minimises potential clash
//    with a concurrent update to the same key in the cluster
CacheValue cacheValue = new CacheValue(marshaller.objectToByteBuffer(value), 1)

// Finally, store it in the cache
cache.put(bytesKey, cacheValue);

Data Stored Via Remote Cache Store

Other times, Hot Rod server might be storing data coming from a RemoteCacheStore, rather than user code. In this case, there're a couple of differences to the code above. First of all, the marshaller is slightly different. Instead, the RemoteCacheStore uses the VersionAwareMarshaller which all it does is add Infinispan version information to the byte array generated. The second difference is that RemoteCacheStore stores internal cache entry classes, which apart from the value part, they contain other extra information. So, any code trying to read these directly from the Hot Rod server would need to take in account. For example, to read data from such Hot Rod server:

import org.infinispan.marshall.VersionAwareMarshaller;
import org.infinispan.util.ByteArrayKey;
import org.infinispan.server.core.CacheValue;
import org.infinispan.container.entries.CacheEntry;
...

// Create a new instance of the marshaller
VersionAwareMarshaller marshaller = new VersionAwareMarshaller();
Object key = ...

// Take the cache key and convert into a byte array,
// and wrap it with an instance of ByteArrayKey
ByteArrayKey bytesKey = new ByteArrayKey(marshaller.objectToByteBuffer(key));

// Internally, Hot Rod stores values wrapped in a CacheValue, so retrieve it
CacheValue cacheValue = (CacheValue) cache.get(bytesKey);

// However, in this case the data part of CacheValue does not contain directly
// the value Instead, it contains an instance of CacheEntry, so we need to 
// unmarshall that and then get the actual value
CacheEntry cacheEntry = (CacheEntry) 
   marshaller.objectFromByteBuffer(cacheValue.data()); 
Object value = cacheEntry.getValue();

And to actually write data back into the Hot Rod server directly:

import org.infinispan.marshall.VersionAwareMarshaller;
import org.infinispan.util.ByteArrayKey;
import org.infinispan.server.core.CacheValue;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.entries.InternalEntryFactory;
...

// Create a new instance of the marshaller:
VersionAwareMarshaller marshaller = new VersionAwareMarshaller();
Object key = ...
Object value = ...

// Take the cache key and convert into a byte array
ByteArrayKey bytesKey = new ByteArrayKey(marshaller.objectToByteBuffer(key));

// With the value to store, a new CacheEntry instance needs to be created:
CacheEntry cacheEntry = InternalEntryFactory.create(bytesKey, value, ...)

// Internally, Hot Rod stores values wrapped in a CacheValue, so create instance
// Remember that you need to give it a version number, so either:
// 1. Increment previous value's version
// 2. Or generate a new version number that minimises potential clash
//    with a concurrent update to the same key in the cluster
CacheValue cacheValue = new CacheValue(
   marshaller.objectToByteBuffer(cacheEntry), 1)

// Finally, store it in the cache
cache.put(bytesKey, cacheValue);
JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-11 09:16:56 UTC, last content change 2013-07-08 14:21:21 UTC.